using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Reflection;
using Renamer.Properties;
using Renamer.Forms;
using System.Text.RegularExpressions;

namespace Renamer
{
    public partial class FormMain : Form
    {

        bool processing;
        int filesFound;
        int filesProcessed;
        int filesError;
        bool statePaused;

        List<string[]> ErrorLog;

        void inicializeCounters()
        {
            filesFound = 0;
            filesProcessed = 0;
            filesError = 0;
            ErrorLog = new List<string[]>();
            updateStatus("-");
        }

        void AppendToLog(string ErrorType, string ErrorMessage, string Filepath)
        {
            ErrorLog.Add(new string[] { ErrorType, ErrorMessage, Filepath });
        }

        public FormMain()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            #region Set Application Title
            this.Text = Assembly.GetExecutingAssembly().GetName().Name + " (v" + Assembly.GetExecutingAssembly().GetName().Version.Major.ToString() + "." + Assembly.GetExecutingAssembly().GetName().Version.Minor.ToString() /*+ " build " + Assembly.GetExecutingAssembly().GetName().Version.Build.ToString()*/ + ")";
            #endregion

            #region Select last selected tab
            if (Settings.Default.Setting_LastSelectedTabIndex <= tabControl1.TabCount)
            {
                tabControl1.SelectedIndex = Settings.Default.Setting_LastSelectedTabIndex;
                SelectCorrespondingMenuItem();
            }
            #endregion
        }

        private void btnBrawse5_Click(object sender, EventArgs e)
        {
            folderBrowserDialog1.SelectedPath = txtPath.Text;
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
            {
                txtPath.Text = folderBrowserDialog1.SelectedPath;
            }
        }

        private string getCapitalizedString(string inp)
        {
            try
            {
                string ret = "";
                string[] split = inp.ToLower(Application.CurrentCulture).Split(new char[] { ' ' });
                for (int n = 0; n < split.Length; n++)
                {
                    if (split[n].Length > 0)
                    {
                        StringBuilder sb = new StringBuilder(split[n]);
                        sb[0] = Char.ToUpper(sb[0]);
                        ret += sb.ToString() + " ";
                    }
                }
                ret = ret.TrimEnd(new char[] { ' ' });
                return ret;
            }
            catch { return inp; }
        }

        void updateStatus(string Filename)
        {
            lblInfoFileName.Text = Filename;
            lblInfoFilesFound.Text = filesFound.ToString();
            lblInfoFilesProcessed.Text = filesProcessed.ToString();
            lblInfoProcessingErrors.Text = filesError.ToString();
            Application.DoEvents();
        }

        void MoveFile(string FileFrom, string FileTo)
        {
            bool exceptionRaised = false;
            string ErrorType = "";
            string ErrorMessage = "";
            try
            {
                File.Move(FileFrom, FileTo);
                filesProcessed++;
            }
            catch (ArgumentException ex)
            {
                exceptionRaised = true;
                ErrorType = "Argument Exception";
                ErrorMessage = ex.Message;
                filesError++;
            }
            catch (UnauthorizedAccessException ex)
            {
                exceptionRaised = true;
                ErrorType = "File Cannot Be Accessed";
                ErrorMessage = ex.Message;
                filesError++;
            }
            catch (FileNotFoundException ex)
            {
                exceptionRaised = true;
                ErrorType = "File Not Found";
                ErrorMessage = ex.Message;
                filesError++;
            }
            catch (PathTooLongException ex)
            {
                exceptionRaised = true;
                ErrorType = "Path Too Long";
                ErrorMessage = ex.Message;
                filesError++;
            }
            catch (DirectoryNotFoundException ex)
            {
                exceptionRaised = true;
                ErrorType = "Directory Not Found";
                ErrorMessage = ex.Message;
                filesError++;
            }
            catch (IOException ex)
            {
                exceptionRaised = true;
                ErrorType = "General I/O Exception";
                ErrorMessage = ex.Message;
                filesError++;
            }
            if (exceptionRaised)
            { AppendToLog(ErrorType, ErrorMessage, FileFrom); }
            updateStatus(FileFrom);
        }


        void processDir_Replace(string path, bool dosub, string sPattern)
        {
            string[] files = Directory.GetFiles(path, sPattern);
            foreach (string file in files)
            {
                filesFound++;
                Application.DoEvents();
                string fnOnly = Path.GetFileNameWithoutExtension(file);
                string fnFull = Path.GetFileName(file);
                string fnDir = Path.GetDirectoryName(file);
                if (!fnDir.EndsWith("\\", StringComparison.Ordinal)) { fnDir += "\\"; }
                updateStatus(fnFull);
                string old = fnFull;
                if (chkAsRegEx.Checked)
                {
                    Regex r = new Regex(txtFrom.Text);
                    MatchCollection matches = r.Matches(fnFull);
                    foreach (Match match in matches)
                    { fnFull = fnFull.Replace(match.Value, txtTo.Text); }
                }
                else
                { fnFull = fnFull.Replace(txtFrom.Text, txtTo.Text); }
                if (old != fnFull)
                {
                    MoveFile(file, fnDir + fnFull);
                }
                if (CheckPauseStop()) { break; }
            }

            if (dosub)
            {
                string[] folders = Directory.GetDirectories(path);
                foreach (string dir in folders)
                {
                    Application.DoEvents();
                    processDir_Replace(dir, dosub, sPattern);
                    Application.DoEvents();
                    if (CheckPauseStop()) { break; }
                }
            }
        }

        void processDir_Capitalize(string path, bool dosub, string sPattern)
        {
            string[] files = Directory.GetFiles(path, sPattern);
            foreach (string file in files)
            {
                filesFound++;
                Application.DoEvents();
                string fnOnly = Path.GetFileNameWithoutExtension(file);
                string fnFull = Path.GetFileName(file);
                string fnDir = Path.GetDirectoryName(file);
                if (!fnDir.EndsWith("\\", StringComparison.Ordinal)) { fnDir += "\\"; }
                updateStatus(fnFull);
                string old = fnOnly;
                fnOnly = getCapitalizedString(fnOnly);
                if (old != fnOnly)
                {
                    string fnExt = Path.GetExtension(file);
                    MoveFile(file, fnDir + fnOnly + fnExt);
                }
                if (CheckPauseStop()) { break; }
            }

            if (dosub)
            {
                string[] folders = Directory.GetDirectories(path);
                foreach (string dir in folders)
                {
                    Application.DoEvents();
                    processDir_Capitalize(dir, dosub, sPattern);
                    Application.DoEvents();
                    if (CheckPauseStop()) { break; }
                }
            }

        }


        private void btnProcess_Click(object sender, EventArgs e)
        {
            if (processing) { MessageBox.Show(this, Settings.Default.text_PrevousTaskRunningMessage, Settings.Default.text_PrevousTaskRunningCaption, MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1); return; }

            #region Check if directory path is invalid
            if (!Directory.Exists(txtPath.Text))
            {
                txtPath.BackColor = Settings.Default.Setting_VisualErrorTextColor;
                txtPath.Focus();
                MessageBox.Show(this, Settings.Default.text_PathDoesNotExistMessage, Settings.Default.text_PathDoesNotExistCaption, MessageBoxButtons.OK, MessageBoxIcon.Stop, MessageBoxDefaultButton.Button1);
                return;
            }
            #endregion

            processing = true;
            statePaused = false;

            #region Enable Disable Buttons
            btnProcess.Visible = false;
            btnPause.Visible = true;
            btnStop.Visible = true;
            #endregion

            try
            {
                if (String.IsNullOrEmpty(txtPattern.Text)) { txtPattern.Text = Settings.Default.Setting_DefaultPattern; }
                inicializeCounters();
                switch (tabControl1.SelectedIndex)
                {
                    case 0:
                        #region Replace From To
                        if (!String.IsNullOrEmpty(txtFrom.Text) && !String.IsNullOrEmpty(txtTo.Text))
                        { processDir_Replace(txtPath.Text, chkDoSub.Checked, txtPattern.Text); }
                        else
                        { MessageBox.Show(this, Settings.Default.text_InvalidParametersMessage, Settings.Default.text_InvalidParametersCaption, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.DefaultDesktopOnly); }
                        #endregion
                        break;

                    case 1:
                        #region Capitalize first letter of the sentence
                        processDir_Capitalize(txtPath.Text, chkDoSub.Checked, txtPattern.Text);
                        #endregion
                        break;

                    default:
                        MessageBox.Show(this, "", "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                        break;
                }
                if (filesError > 0)
                {
                    if (MessageBox.Show(this, "Rename finished, but some errors were detected. Do you want to view the error log?", Settings.Default.Text_ConversionFinished, MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1) == DialogResult.Yes)
                    {
                        FormErrorLog f = new FormErrorLog(ErrorLog);
                        f.ShowDialog();
                    }
                }
                else
                {
                    MessageBox.Show(this, "Rename finished. No errors were detected", Settings.Default.Text_ConversionFinished, MessageBoxButtons.OK, MessageBoxIcon.Information, MessageBoxDefaultButton.Button1);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message, "Exception", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
            }
            processing = false;

            #region Enable Disable Buttons
            btnProcess.Visible = true;
            btnPause.Visible = false;
            btnStop.Visible = false;
            #endregion
        }

        private void txtPath_Click(object sender, EventArgs e)
        {
            txtPath.BackColor = System.Drawing.SystemColors.Window;
        }

        private void txtPath_KeyPress(object sender, KeyPressEventArgs e)
        {
            txtPath_Click(null, null);
        }

        private void txtPath_TextChanged(object sender, EventArgs e)
        {
            txtPath_Click(null, null);
        }

        private void txtPath_MouseClick(object sender, MouseEventArgs e)
        {
            txtPath_Click(null, null);
        }

        private void chkAsRegEx_CheckedChanged(object sender, EventArgs e)
        {
            btnTestRegEx.Visible = chkAsRegEx.Checked;
        }

        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            Settings.Default.Setting_LastSelectedTabIndex = tabControl1.SelectedIndex;

            SelectCorrespondingMenuItem();
        }

        private void SelectCorrespondingMenuItem()
        {
            replaceTextInFilenameToolStripMenuItem.Checked = false;
            capitalizeFirstLetterToolStripMenuItem.Checked = false;
            renameMP3sToolStripMenuItem.Checked = false;

            switch (tabControl1.SelectedIndex)
            {
                case 0: replaceTextInFilenameToolStripMenuItem.Checked = true;
                    break;
                case 1: capitalizeFirstLetterToolStripMenuItem.Checked = true;
                    break;
                case 3: renameMP3sToolStripMenuItem.Checked = true;
                    break;

            }
        }

        bool CheckPauseStop()
        {
            if (!processing) { return true; }
            while (statePaused) { Application.DoEvents(); }
            return false;
        }

        private void btnPause_Click(object sender, EventArgs e)
        {
            statePaused = !statePaused;
            btnPause.Text = statePaused ? "Continue" : "Pause";
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            processing = false;
        }

        private void btnTestRegEx_Click(object sender, EventArgs e)
        {
            FormRegexTest f = new FormRegexTest(txtFrom.Text);
            if (f.ShowDialog() == DialogResult.OK)
            { txtFrom.Text = f.ResultRegularExpression; }
        }

        private void txtFrom_Click(object sender, EventArgs e)
        {
            txtFrom.BackColor = System.Drawing.SystemColors.Window;
        }

        private void txtFrom_KeyPress(object sender, KeyPressEventArgs e)
        {
            txtFrom_Click(null, null);
        }

        private void chkAsRegEx_Click(object sender, EventArgs e)
        {
            txtFrom_Click(null, null);
        }

        private void chkCreateBackup_CheckedChanged(object sender, EventArgs e)
        {
            Settings.Default.Settings_CreateUndo = chkCreateUndo.Checked;
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (processing)
            {
                if (MessageBox.Show(this, Settings.Default.Text_RenameInProcessDoYouWantToExit_Message, Settings.Default.Text_RenameInProcessDoYouWantToExit_Title, MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2, MessageBoxOptions.DefaultDesktopOnly) == DialogResult.Yes)
                { e.Cancel = true; }
                else { e.Cancel = false; }
            }
            else { e.Cancel = false; }
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new FormAbout().ShowDialog();
        }

        private void replaceTextInFilenameToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tabControl1.SelectedIndex = 0;
        }

        private void capitalizeFirstLetterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tabControl1.SelectedIndex = 1;
        }

        private void renameMP3sToolStripMenuItem_Click(object sender, EventArgs e)
        {
            tabControl1.SelectedIndex = 2;
        }
    }
}